package rpc

import (
	"fmt"
	"github.com/golang/protobuf/proto"
	error2 "leaf/core/error"
	"leaf/core/log"
	. "leaf/core/msg"
	"leaf/core/network"
	"reflect"
)

var (
	Error_HandlerNotFind   = fmt.Errorf("handle not find")
	Error_RequestTypeWrong = fmt.Errorf("handle request type wrong")
	Error_ReplyTypeWrong   = fmt.Errorf("handle reply type wrong")
)

func Register(methodStr string, st reflect.Type, requestMsg proto.Message, replyMsg proto.Message, method RpcMethod) {
	processer.Register(st, requestMsg, replyMsg, methodStr, method)
}

func RegisterService(s interface{}) {
	processer.RegisterService(s)
}

func Connect(addr string, uniqueid string, disconnecter IRpcConnect) *RpcClient {
	rpcClient := NewRpcClient(uniqueid, disconnecter)
	rpcClient.Conn = network.NewTcpConn(addr, nil, rpcClient)
	if rpcClient.Conn == nil {
		log.Fatal("RpcConnect err:rpc Conn is nil")
	}
	rpcClient.Conn.Start()

	return rpcClient
}

func StartServer(addr string) *RpcServer {
	s := network.NewTcpServer(addr, 1024, func(conn network.Conn) network.Agent {
		return &RpcServerClient{
			Conn:     conn,
			rpcCalls: make(map[uint32]*RpcCall),
		}
	})

	s.OnAccept = func(conn network.Conn) {
		agent := conn.GetAgent()
		if agent == nil {
			log.Fatal("rpc listen err:%v", "agent is nil")
		}
		var client, ok = agent.(*RpcServerClient)
		if !ok {
			log.Fatal("rpc listen err:%v", "agent is nil")
		}
		client.SendPotoMsg(processer.rpcHandlerInfos)
	}
	return &RpcServer{TcpServer: s}
}

func LocalCall(method string, request proto.Message, reply proto.Message) error {
	serv, handler := processer.GetHandler(method)
	if handler == nil {
		log.Error("LocalCall err:%v method:%v", Error_HandlerNotFind, method)
		return Error_HandlerNotFind
	}

	if handler.RequestId != 0 && handler.RequestId != GetMessageId(reflect.TypeOf(request)) {
		log.Error("LocalCall err:%v method:%v", Error_RequestTypeWrong, method)
		return Error_RequestTypeWrong
	}

	if handler.ReplyId != 0 && handler.ReplyId != GetMessageId(reflect.TypeOf(reply)) {
		log.Error("LocalCall err:%v method:%v", Error_ReplyTypeWrong, method)
		return Error_ReplyTypeWrong
	}

	pmsg := &PMsg{
		Reply:   &Message{Msg: reply},
		Request: &Message{Msg: request},
	}
	serv.(IServicRpcFilter).GetServicRpc().Exec(handler, pmsg, true)
	if err := error2.GetError(pmsg.Reply.Code); err != nil {
		return err
	}

	return nil
}

func LocalCast(method string, request proto.Message) error {
	serv, handler := processer.GetHandler(method)
	if handler == nil {
		log.Error("LocalCast err:%v :%v", Error_HandlerNotFind, method)
		return Error_HandlerNotFind
	}

	if handler.RequestId != GetMessageId(reflect.TypeOf(request)) {
		log.Error("LocalCast err:%v :%v", Error_RequestTypeWrong, method)
		return Error_RequestTypeWrong
	}

	if handler.ReplyId != 0 {
		log.Error("LocalCast err:%v :%v", Error_ReplyTypeWrong, method)
		return Error_ReplyTypeWrong
	}

	serv.(IServicRpcFilter).GetServicRpc().Exec(handler, &PMsg{
		Request: &Message{Msg: request},
	}, false)
	return nil
}
